package com.molichuxing.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.molichuxing.entity.MaintenanceEmailDto;
import com.molichuxing.exception.MaintenanceRemindCountKey;
import com.molichuxing.framework.result.ResponseResult;
import com.molichuxing.framework.utils.*;
import com.molichuxing.service.CarMaintenanceDateJobService;
import com.molichuxing.services.business.dto.response.CarOrderBizDto;
import com.molichuxing.services.business.service.OrderBizService;
import com.molichuxing.services.business.service.SmsBizService;
import com.molichuxing.services.infrastructure.dto.request.create.MessageCenterCreateDto;
import com.molichuxing.services.infrastructure.dto.request.create.NotifyPushCreateDto;
import com.molichuxing.services.infrastructure.dto.response.*;
import com.molichuxing.services.infrastructure.service.*;
import com.molichuxing.services.property.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: renzhengyu
 * @Description:
 * @Date: Created in 10:22 2019/12/19
 * @Modified By:
 **/
@Service("carMaintenanceDateJobService")
public class CarMaintenanceDateJobServiceImpl implements CarMaintenanceDateJobService {

    private static final Logger logger = LoggerFactory.getLogger(CarMaintenanceDateJobServiceImpl.class);

    @Resource
    private CarService carService;
    @Resource
    private MaintenanceConfigService maintenanceConfigService;
    @Resource
    private MaintenanceService maintenanceService;
    @Resource
    private OrderBizService orderBizService;
    @Resource
    private EntrepotStorageService entrepotStorageService;
    @Resource
    private StockStoreService stockStoreService;
    @Resource
    private StoreService storeService;
    @Resource
    private DealerService dealerService;
    @Resource
    private UserService userService;
    @Resource
    private MessageTemplateService messageTemplateService;
    @Resource
    private RiskEmailService riskEmailService;
    @Resource
    private SmsBizService smsBizService;
    @Resource
    private NotifyPushService notifyPushService;
    @Resource
    private MessageCenterService messageCenterService;
    @Resource
    private IovCarService iovCarService;
    @Resource
    private RedisUtil redisUtil;

    @Value("${email.account}")
    private String emailAccount;

    @Value("${email.password}")
    private String emailPassword;

    @Value("${dingTalk.maintenance.url}")
    private String dingTalkMaintenanceUrl;

    @Value("${dingTalk.maintenance.error.url}")
    private String dingTalkMaintenanceErrorUrl;

    @Value("${profiles.active.explain}")
    private String ACTIVE_EXPLAIN;

    private static final String pushMaintenanceRemind="push_maintenance_remind";
    private static final String instationMaintenanceRemind="instation_maintenance_remind";
    private static final String dingTalkMaintenanceWarning="dingTalk_maintenance_warning";
    private static final String dingTalkMaintenanceOvertime="dingTalk_maintenance_overtime";
    private static final String emailMaintenanceWarning="email_maintenance_warning";
    private static final String emailMaintenanceOvertime="email_maintenance_overtime";

    /**
     * 20%
     */
    private final BigDecimal TWENTY_PERCENT = new BigDecimal("0.2");
    /**
     * 10%
     */
    private final BigDecimal TEN_PERCENT = new BigDecimal("0.1");

    /**
     * 保养数据查询
     * @return
     * @throws Exception
     */
    @Override
    public Boolean getCarMaintenanceDateHandler() throws Exception {
        //所有要查询的车辆
        List<CarDto> carAllDtoList = new ArrayList<>();

        //无业务车辆
        List<CarDto> carNoBusinessDtoList = carService.getCarsByBusinessType(CarsBusinessTypeEnum.NO_BUSINESS);
        if(null != carNoBusinessDtoList && carNoBusinessDtoList.size() > 0 ){
            carAllDtoList.addAll(carNoBusinessDtoList);
        }

        //专属车辆
        List<CarDto> carExclusiveDtoList = carService.getCarsByBusinessType(CarsBusinessTypeEnum.EXCLUSIVE);
        if(null != carExclusiveDtoList && carExclusiveDtoList.size() > 0 ){
            carAllDtoList.addAll(carExclusiveDtoList);
        }
        // 订阅车辆
        List<CarDto> carSubscribeDtoList = carService.getCarsByBusinessType(CarsBusinessTypeEnum.SUBSCRIBE);
        if(null != carSubscribeDtoList && carSubscribeDtoList.size() > 0 ){
            carAllDtoList.addAll(carSubscribeDtoList);
        }

        //保养配置
        Map<Integer,MaintenanceConfigDto> maintenanceConfig = new HashMap<>();

        //预警保养邮件List
        List<MaintenanceEmailDto> warningEmailDtoList= new ArrayList<>();
        //超期保养邮件List
        List<MaintenanceEmailDto> overTimeEmailDtoList= new ArrayList<>();
        //查询模板信息
        Map<String,MessageTemplateDto> dingAndEmailByKeys = getDingAndEmailByKeys();
        //无法获取当前行驶里程 车辆
        List<Integer> carErrorList = new ArrayList<>();

        for (CarDto carDto:carAllDtoList) {

            //获取当前行驶里程
            Integer odoMileage = iovCarService.getOdoMileage(carDto.getVin());

            if(null == odoMileage){
                //无法获取当前行驶里程 车辆
                carErrorList.add(carDto.getId());
                continue;
            }
            //当前已行驶里程
            BigDecimal nowMileage = new BigDecimal(odoMileage);

            if(null == maintenanceConfig.get(carDto.getVehicleId())){
                MaintenanceConfigDto maintenanceConfigDto = maintenanceConfigService.getMaintenanceConfigByVehicleId(carDto.getVehicleId());
                maintenanceConfig.put(carDto.getVehicleId(),maintenanceConfigDto);
            }
            //根据车辆id 查询保养表中是否有数据
            MaintenanceDto maintenanceDto = maintenanceService.getOneMaintenanceByCarId(carDto.getId());

            if(null != maintenanceDto){
                //有数据，取库里最新的 应保养里程 和 当前行驶里程运算

                //审核中和驳回不处理
                if(MaintenanceStatusEnum.AUDITED.getValue() == maintenanceDto.getStatus() || MaintenanceStatusEnum.AUDIT_REJECTED.getValue() == maintenanceDto.getStatus()){
                    continue;
                }

                //当前日期=应保养日-40天
                if(LocalDate.now().equals(maintenanceDto.getMaintainableDate().minusDays(40).toLocalDate())){
                    //查询车辆是否有对应的订单
                    CarOrderBizDto carOrderBizDto = orderBizService.getUseOrderByCar(carDto.getId(),null);
                    //更新保养
                    updateMaintenanceById(carOrderBizDto,maintenanceDto);

                    //无对应的订单，不发送提醒
                    if(null == carOrderBizDto){
                        //车务邮件附件
                        warningEmailDtoList.add(toMaintenanceEmailDto(1,carDto,carOrderBizDto,maintenanceDto,null,nowMileage));
                        continue;
                    }


                    if(OrderTypeEnum.SUBSCRIBE.equals(carOrderBizDto.getOrderType()) &&
                            (carOrderBizDto.getLeaseExpire().isBefore(maintenanceDto.getMaintainableDate().toLocalDate())  || carOrderBizDto.getLeaseExpire().equals(maintenanceDto.getMaintainableDate().toLocalDate()))){
                        //车务邮件附件
                        warningEmailDtoList.add(toMaintenanceEmailDto(1,carDto,carOrderBizDto,maintenanceDto,null,nowMileage));

                    }

                    //发送消息
                    //查询是否存在超里程提醒
                    String timeCount = redisUtil.get(MaintenanceRemindCountKey.getMileageRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                    if(StringUtils.isBlank(timeCount)){
                        //查询时间提醒次数
                        String mileageCount = redisUtil.get(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                        //同一用户同一保养最多提醒用户两次
                        if(StringUtils.isBlank(mileageCount) || Integer.valueOf(mileageCount) <= 2){
                            // 如果车辆当前为专属里程用车中的订单时直接发送
                            if(OrderTypeEnum.EXCLUSIVEL.equals(carOrderBizDto.getOrderType()) ){
                                //发送短信，推送和站内信
                                sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                //计数器+1
                                redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                            }else if(OrderTypeEnum.SUBSCRIBE.equals(carOrderBizDto.getOrderType())){
                                if(carOrderBizDto.getLeaseExpire().isAfter(maintenanceDto.getMaintainableDate().toLocalDate())){
                                    //如果车辆当前为订阅里程用车中的订单 && 订单截止日>应保养时间-40
                                    //发送短信，推送和站内信
                                    sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                    //计数器+1
                                    redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                                }
                            }
                        }
                    }
                    //当前日期=应保养日-30日
                }else if(LocalDate.now().equals(maintenanceDto.getMaintainableDate().minusDays(30).toLocalDate())){

                    //查询车辆是否有对应的订单
                    CarOrderBizDto carOrderBizDto = orderBizService.getUseOrderByCar(carDto.getId(),null);
                    //更新保养
                    updateMaintenanceById(carOrderBizDto,maintenanceDto);

                    //无对应的订单，不发送提醒
                    if(null == carOrderBizDto){
                        //车务邮件附件
                        warningEmailDtoList.add(toMaintenanceEmailDto(1,carDto,carOrderBizDto,maintenanceDto,null,nowMileage));
                        continue;
                    }

                    if(OrderTypeEnum.SUBSCRIBE.equals(carOrderBizDto.getOrderType())&&
                            (carOrderBizDto.getLeaseExpire().isBefore(maintenanceDto.getMaintainableDate().toLocalDate())  || carOrderBizDto.getLeaseExpire().equals(maintenanceDto.getMaintainableDate().toLocalDate()))){
                        //车务邮件附件
                        warningEmailDtoList.add(toMaintenanceEmailDto(1,carDto,carOrderBizDto,maintenanceDto,null,nowMileage));

                    }

                    //发送消息
                    //查询是否存在超里程提醒
                    String timeCount = redisUtil.get(MaintenanceRemindCountKey.getMileageRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                    if(StringUtils.isBlank(timeCount)){
                        //查询时间提醒次数
                        String mileageCount = redisUtil.get(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                        //同一用户同一保养最多提醒用户两次
                        if(StringUtils.isBlank(mileageCount) || Integer.valueOf(mileageCount) <= 2){
                            // 如果车辆当前为专属里程用车中的订单时直接发送
                            if(OrderTypeEnum.EXCLUSIVEL.equals(carOrderBizDto.getOrderType()) ){
                                //发送短信，推送和站内信
                                sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                //计数器+1
                                redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                            }else if(OrderTypeEnum.SUBSCRIBE.equals(carOrderBizDto.getOrderType())){
                                if(carOrderBizDto.getLeaseExpire().isAfter(maintenanceDto.getMaintainableDate().toLocalDate())){
                                    //如果车辆当前为订阅里程用车中的订单 && 订单截止日>应保养时间-40
                                    //发送短信，推送和站内信
                                    sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                    //计数器+1
                                    redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                                }
                            }
                        }
                    }



                    //当前日期>=应保养日-20日 && 当前日期 <= 应保养日
                }else if((LocalDate.now().isAfter(maintenanceDto.getMaintainableDate().minusDays(20).toLocalDate()) || LocalDate.now().equals(maintenanceDto.getMaintainableDate().minusDays(20).toLocalDate()))
                && (LocalDate.now().isBefore(maintenanceDto.getMaintainableDate().toLocalDate()) || LocalDate.now().equals(maintenanceDto.getMaintainableDate().toLocalDate()))){

                    //查询车辆是否有对应的订单
                    CarOrderBizDto carOrderBizDto = orderBizService.getUseOrderByCar(carDto.getId(),null);
                    //更新保养
                    updateMaintenanceById(carOrderBizDto,maintenanceDto);

                    //无对应的订单，不发送提醒
                    if(null == carOrderBizDto){
                        //车务邮件附件
                        warningEmailDtoList.add(toMaintenanceEmailDto(1,carDto,carOrderBizDto,maintenanceDto,null,nowMileage));
                        continue;
                    }


                    if(OrderTypeEnum.EXCLUSIVEL.equals(carOrderBizDto.getOrderType()) &&
                            (carOrderBizDto.getLeaseExpire().isBefore(maintenanceDto.getMaintainableDate().toLocalDate())  || carOrderBizDto.getLeaseExpire().equals(maintenanceDto.getMaintainableDate().toLocalDate()))){
                        //车务邮件附件
                        warningEmailDtoList.add(toMaintenanceEmailDto(1,carDto,carOrderBizDto,maintenanceDto,null,nowMileage));

                    }else if(OrderTypeEnum.SUBSCRIBE.equals(carOrderBizDto.getOrderType()) &&
                            (carOrderBizDto.getLeaseExpire().isBefore(maintenanceDto.getMaintainableDate().toLocalDate())  || carOrderBizDto.getLeaseExpire().equals(maintenanceDto.getMaintainableDate().toLocalDate()))){
                        //车务邮件附件
                        warningEmailDtoList.add(toMaintenanceEmailDto(1,carDto,carOrderBizDto,maintenanceDto,null,nowMileage));

                    }


                    //发送消息
                    //查询是否存在超里程提醒
                    String timeCount = redisUtil.get(MaintenanceRemindCountKey.getMileageRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                    if(StringUtils.isBlank(timeCount)){
                        //查询时间提醒次数
                        String mileageCount = redisUtil.get(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                        //同一用户同一保养最多提醒用户两次
                        if(StringUtils.isBlank(mileageCount) || Integer.valueOf(mileageCount) <= 2){
                            // 如果车辆当前为专属里程用车中的订单时直接发送
                            if(OrderTypeEnum.EXCLUSIVEL.equals(carOrderBizDto.getOrderType()) ){
                                //发送短信，推送和站内信
                                sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                //计数器+1
                                redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                            }else if(OrderTypeEnum.SUBSCRIBE.equals(carOrderBizDto.getOrderType())){
                                if(carOrderBizDto.getLeaseExpire().isAfter(maintenanceDto.getMaintainableDate().toLocalDate())){
                                    //如果车辆当前为订阅里程用车中的订单 && 订单截止日>应保养时间-40
                                    //发送短信，推送和站内信
                                    sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                    //计数器+1
                                    redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                                }
                            }
                        }
                    }

                    //当前日期>应保养日
                }else if(LocalDate.now().isAfter(maintenanceDto.getMaintainableDate().toLocalDate())){
                    //查询车辆是否有对应的订单
                    CarOrderBizDto carOrderBizDto = orderBizService.getUseOrderByCar(carDto.getId(),null);
                    //更新保养
                    updateMaintenanceById(carOrderBizDto,maintenanceDto);

                    //无对应的订单，不发送提醒
                    if(null == carOrderBizDto){
                        //车务邮件附件
                        overTimeEmailDtoList.add(toMaintenanceEmailDto(1,carDto,carOrderBizDto,maintenanceDto,null,nowMileage));
                        continue;
                    }

                    //车务邮件附件
                    overTimeEmailDtoList.add(toMaintenanceEmailDto(1,carDto,carOrderBizDto,maintenanceDto,null,nowMileage));




                    //发送消息
                    //查询是否存在超里程提醒
                    String timeCount = redisUtil.get(MaintenanceRemindCountKey.getMileageRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                    if(StringUtils.isBlank(timeCount)){
                        //查询时间提醒次数
                        String mileageCount = redisUtil.get(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                        //同一用户同一保养最多提醒用户两次
                        if(StringUtils.isBlank(mileageCount) || Integer.valueOf(mileageCount) <= 2){
                            // 如果车辆当前为专属里程用车中的订单时直接发送
                            if(OrderTypeEnum.EXCLUSIVEL.equals(carOrderBizDto.getOrderType()) ){
                                //发送短信，推送和站内信
                                sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                //计数器+1
                                redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                            }else if(OrderTypeEnum.SUBSCRIBE.equals(carOrderBizDto.getOrderType())){
                                if(carOrderBizDto.getLeaseExpire().isAfter(maintenanceDto.getMaintainableDate().toLocalDate())){
                                    //如果车辆当前为订阅里程用车中的订单 && 订单截止日>应保养时间-40
                                    //发送短信，推送和站内信
                                    sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                    //计数器+1
                                    redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceDto.getId(),carDto.getId()));
                                }
                            }
                        }
                    }
                }


            }else{
                //无数据，取库里最新的 应保养里程 和 当前行驶里程运算

                LocalDate maintenanceDay = carDto.getPurchaseDate().plusDays(maintenanceConfig.get(carDto.getVehicleId()).getMaintenanceTime()).toLocalDate();

                //当前日期=应保养日-40天
                if(LocalDate.now().equals(maintenanceDay.minusDays(40))){
                    //查询车辆是否有对应的订单
                    CarOrderBizDto carOrderBizDto = orderBizService.getUseOrderByCar(carDto.getId(),null);
                    //创建保养
                    Integer maintenanceId = createMaintenance(carOrderBizDto,carDto,maintenanceConfig);

                    //无对应的订单，不发送提醒
                    if(null == carOrderBizDto){
                        //车务邮件附件
                        warningEmailDtoList.add(toMaintenanceEmailDto(2,carDto,carOrderBizDto,null,maintenanceConfig,nowMileage));
                        continue;
                    }

                    if(OrderTypeEnum.SUBSCRIBE.equals(carOrderBizDto.getOrderType()) &&
                            (carOrderBizDto.getLeaseExpire().isBefore(maintenanceDay)  || carOrderBizDto.getLeaseExpire().equals(maintenanceDay))){
                        //车务邮件附件
                        warningEmailDtoList.add(toMaintenanceEmailDto(2,carDto,carOrderBizDto,null,maintenanceConfig,nowMileage));

                    }

                    // 发送消息
                    //查询是否超里程提醒
                    String timeCount = redisUtil.get(MaintenanceRemindCountKey.getMileageRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                    if(StringUtils.isBlank(timeCount)){
                        //查询时间提醒次数
                        String mileageCount = redisUtil.get(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                        if(StringUtils.isBlank(mileageCount) || Integer.valueOf(mileageCount) <= 2){
                            // 如果车辆当前为专属里程用车中的订单时直接发送
                            if(OrderTypeEnum.EXCLUSIVEL.equals(carOrderBizDto.getOrderType()) ){
                                //发送短信，推送和站内信
                                sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                //计数器+1
                                redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                            }else if(OrderTypeEnum.SUBSCRIBE.equals(carOrderBizDto.getOrderType())){
                                if(carOrderBizDto.getLeaseExpire().isAfter(maintenanceDay)){
                                    //如果车辆当前为订阅里程用车中的订单 && 订单截止日>应保养时间-40
                                    //发送短信，推送和站内信
                                    sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                    //计数器+1
                                    redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                                }
                            }
                        }
                    }
                    //当前日期=应保养日-30日
                }else if(LocalDate.now().equals(maintenanceDay.minusDays(30))){
                    //查询车辆是否有对应的订单
                    CarOrderBizDto carOrderBizDto = orderBizService.getUseOrderByCar(carDto.getId(),null);
                    //创建保养
                    Integer maintenanceId = createMaintenance(carOrderBizDto,carDto,maintenanceConfig);

                    //无对应的订单，不发送提醒
                    if(null == carOrderBizDto){
                        //车务邮件附件
                        warningEmailDtoList.add(toMaintenanceEmailDto(2,carDto,carOrderBizDto,null,maintenanceConfig,nowMileage));
                        continue;
                    }

                    if(OrderTypeEnum.SUBSCRIBE.equals(carOrderBizDto.getOrderType()) &&
                            (carOrderBizDto.getLeaseExpire().isBefore(maintenanceDay)  || carOrderBizDto.getLeaseExpire().equals(maintenanceDay))){
                        //车务邮件附件
                        warningEmailDtoList.add(toMaintenanceEmailDto(2,carDto,carOrderBizDto,null,maintenanceConfig,nowMileage));

                    }

                    // 发送消息
                    //查询是否超里程提醒
                    String timeCount = redisUtil.get(MaintenanceRemindCountKey.getMileageRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                    if(StringUtils.isBlank(timeCount)){
                        //查询时间提醒次数
                        String mileageCount = redisUtil.get(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                        if(StringUtils.isBlank(mileageCount) || Integer.valueOf(mileageCount) <= 2){
                            // 如果车辆当前为专属里程用车中的订单时直接发送
                            if(OrderTypeEnum.EXCLUSIVEL.equals(carOrderBizDto.getOrderType()) ){
                                //发送短信，推送和站内信
                                sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                //计数器+1
                                redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                            }else if(OrderTypeEnum.SUBSCRIBE.equals(carOrderBizDto.getOrderType())){
                                if(carOrderBizDto.getLeaseExpire().isAfter(maintenanceDay)){
                                    //如果车辆当前为订阅里程用车中的订单 && 订单截止日>应保养时间-40
                                    //发送短信，推送和站内信
                                    sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                    //计数器+1
                                    redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                                }
                            }
                        }
                    }



                    //当前日期>=应保养日-20日 && 当前日期 <= 应保养日
                }else if((LocalDate.now().isAfter(maintenanceDay.minusDays(20)) || LocalDate.now().equals(maintenanceDay.minusDays(20)))
                        && (LocalDate.now().isBefore(maintenanceDay) || LocalDate.now().equals(maintenanceDay))){
                    //查询车辆是否有对应的订单
                    CarOrderBizDto carOrderBizDto = orderBizService.getUseOrderByCar(carDto.getId(),null);
                    //创建保养
                    Integer maintenanceId = createMaintenance(carOrderBizDto,carDto,maintenanceConfig);

                    //无对应的订单，不发送提醒
                    if(null == carOrderBizDto){
                        //车务邮件附件
                        warningEmailDtoList.add(toMaintenanceEmailDto(2,carDto,carOrderBizDto,null,maintenanceConfig,nowMileage));
                        continue;
                    }

                    if(OrderTypeEnum.EXCLUSIVEL.equals(carOrderBizDto.getOrderType()) &&
                            (carOrderBizDto.getLeaseExpire().isBefore(maintenanceDay)  || carOrderBizDto.getLeaseExpire().equals(maintenanceDay))){
                        //车务邮件附件
                        warningEmailDtoList.add(toMaintenanceEmailDto(2,carDto,carOrderBizDto,null,maintenanceConfig,nowMileage));

                    }else if(OrderTypeEnum.SUBSCRIBE.equals(carOrderBizDto.getOrderType()) &&
                            (carOrderBizDto.getLeaseExpire().isBefore(maintenanceDay)  || carOrderBizDto.getLeaseExpire().equals(maintenanceDay))){
                        //车务邮件附件
                        warningEmailDtoList.add(toMaintenanceEmailDto(2,carDto,carOrderBizDto,null,maintenanceConfig,nowMileage));

                    }

                    // 发送消息
                    //查询是否超里程提醒
                    String timeCount = redisUtil.get(MaintenanceRemindCountKey.getMileageRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                    if(StringUtils.isBlank(timeCount)){
                        //查询时间提醒次数
                        String mileageCount = redisUtil.get(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                        if(StringUtils.isBlank(mileageCount) || Integer.valueOf(mileageCount) <= 2){
                            // 如果车辆当前为专属里程用车中的订单时直接发送
                            if(OrderTypeEnum.EXCLUSIVEL.equals(carOrderBizDto.getOrderType()) ){
                                //发送短信，推送和站内信
                                sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                //计数器+1
                                redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                            }else if(OrderTypeEnum.SUBSCRIBE.equals(carOrderBizDto.getOrderType())){
                                if(carOrderBizDto.getLeaseExpire().isAfter(maintenanceDay)){
                                    //如果车辆当前为订阅里程用车中的订单 && 订单截止日>应保养时间-40
                                    //发送短信，推送和站内信
                                    sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                    //计数器+1
                                    redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                                }
                            }
                        }
                    }
                    //当前日期>应保养日
                }else if(LocalDate.now().isAfter(maintenanceDay)){
                    //查询车辆是否有对应的订单
                    CarOrderBizDto carOrderBizDto = orderBizService.getUseOrderByCar(carDto.getId(),null);
                    //创建保养
                    Integer maintenanceId = createMaintenance(carOrderBizDto,carDto,maintenanceConfig);

                    //无对应的订单，不发送提醒
                    if(null == carOrderBizDto){
                        //车务邮件附件
                        overTimeEmailDtoList.add(toMaintenanceEmailDto(2,carDto,carOrderBizDto,null,maintenanceConfig,nowMileage));
                        continue;
                    }

                    //车务邮件附件
                    overTimeEmailDtoList.add(toMaintenanceEmailDto(2,carDto,carOrderBizDto,null,maintenanceConfig,nowMileage));


                    // 发送消息
                    //查询是否超里程提醒
                    String timeCount = redisUtil.get(MaintenanceRemindCountKey.getMileageRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                    if(StringUtils.isBlank(timeCount)){
                        //查询时间提醒次数
                        String mileageCount = redisUtil.get(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                        if(StringUtils.isBlank(mileageCount) || Integer.valueOf(mileageCount) <= 2){
                            // 如果车辆当前为专属里程用车中的订单时直接发送
                            if(OrderTypeEnum.EXCLUSIVEL.equals(carOrderBizDto.getOrderType()) ){
                                //发送短信，推送和站内信
                                sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                //计数器+1
                                redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                            }else if(OrderTypeEnum.SUBSCRIBE.equals(carOrderBizDto.getOrderType())){
                                if(carOrderBizDto.getLeaseExpire().isAfter(maintenanceDay)){
                                    //如果车辆当前为订阅里程用车中的订单 && 订单截止日>应保养时间-40
                                    //发送短信，推送和站内信
                                    sendNoteAndPush(carOrderBizDto.getUserId(),carDto);
                                    //计数器+1
                                    redisUtil.incr(MaintenanceRemindCountKey.getTimeRemindKey(carOrderBizDto.getUserId(),maintenanceId,carDto.getId()));
                                }
                            }
                        }
                    }
                }
            }

        }

        if(warningEmailDtoList.size() > 0){
            //保养预警发送邮件
            sendMaintenanceEmail(1,dingAndEmailByKeys,warningEmailDtoList);
            //发送钉钉 保养预警
            sendMaintenanceDingTalk(1,dingAndEmailByKeys);
        }

        if(overTimeEmailDtoList.size() > 0){
            //保养超期发送邮件
            sendMaintenanceEmail(2,dingAndEmailByKeys,overTimeEmailDtoList);
            //发送钉钉 保养超期
            sendMaintenanceDingTalk(2,dingAndEmailByKeys);
        }


        if(carErrorList.size() > 0 ){
            //无法获取当前行驶里程的车辆 发送钉钉
            String body = ACTIVE_EXPLAIN.concat("（年份定时）无法获取当前行驶里程的车辆:");
            for (Integer carId:carErrorList) {
                body = body.concat(carId+",");
            }
            DingTalkUtil.execute(dingTalkMaintenanceErrorUrl, body);
        }


        return true;
    }




    /**
     * 组装邮件参数
     * @param type 1：修改， 2：新增
     * @param carDto
     * @param carOrderBizDto
     * @param maintenanceDto
     * @param maintenanceConfig
     * @param nowMileage
     * @return
     * @throws Exception
     */
    private MaintenanceEmailDto toMaintenanceEmailDto(Integer type,CarDto carDto,CarOrderBizDto carOrderBizDto, MaintenanceDto maintenanceDto,Map<Integer,MaintenanceConfigDto> maintenanceConfig,BigDecimal nowMileage) throws Exception {
        MaintenanceEmailDto maintenanceEmailDto = new MaintenanceEmailDto();
        if(null == carOrderBizDto){
            if(1 == carDto.getStockType()){
                //1：中转库 （中转库简称）
                EntrepotStorageDto entrepotStorageDto = entrepotStorageService.getEntrepotStorage(carDto.getStockId());
                if(null == entrepotStorageDto || null == entrepotStorageDto.getShortName()){
                    logger.error("根据库存id查询库存信息为空，库存id："+ carDto.getStockId());
                    throw new Exception("根据库存id查询库存信息为空，库存id："+ carDto.getStockId());
                }else{
                    //车辆所在
                    maintenanceEmailDto.setVehicleLocation(entrepotStorageDto.getShortName());
                }
            }else {
                //2：门店  (经销商简称-门店简称)
                StockStoreDto stockStoreDto = stockStoreService.getStockStore(carDto.getStockId());
                if(null == stockStoreDto || null == stockStoreDto.getStoreId()){
                    logger.error("根据库存id查询关联门店id信息为空，库存id："+ carDto.getStockId());
                    throw new Exception("根据库存id查询关联门店id信息为空，库存id："+ carDto.getStockId());
                }
                StoreDto storeDto = storeService.getStoreById(stockStoreDto.getStoreId());
                if(null == storeDto || null == storeDto.getShortName()){
                    logger.error("根据门店id查询关联门店信息为空，门店id："+ carDto.getStockId());
                    throw new Exception("根据门店id查询关联门店信息为空，门店id："+ carDto.getStockId());
                }
                DealerDto dealerDto = dealerService.getDealerById(storeDto.getDealerId());
                if(null == dealerDto || null == dealerDto.getShortName()){
                    logger.error("根据经销商id查询经销商信息为空，经销商id："+ storeDto.getDealerId());
                    throw new Exception("根据经销商id查询经销商信息为空，经销商id："+ storeDto.getDealerId());
                }
                //车辆所在
                maintenanceEmailDto.setVehicleLocation(dealerDto.getShortName()+ "-" + storeDto.getShortName());

            }
        }else{
            //用户 (经销商简称 - 用户名)
            StoreDto storeDto = storeService.getStoreById(carOrderBizDto.getPlaceStoreId());
            if(null == storeDto || null == storeDto.getShortName()){
                logger.error("根据门店id查询关联门店信息为空，门店id："+ carDto.getStockId());
                throw new Exception("根据门店id查询关联门店信息为空，门店id："+ carDto.getStockId());
            }
            DealerDto dealerDto = dealerService.getDealerById(storeDto.getDealerId());
            if(null == dealerDto || null == dealerDto.getShortName()){
                logger.error("根据经销商id查询经销商信息为空，经销商id："+ storeDto.getDealerId());
                throw new Exception("根据经销商id查询经销商信息为空，经销商id："+ storeDto.getDealerId());
            }
            UserDto userDto = userService.getUser(carOrderBizDto.getUserId());
            if(null == userDto){
                logger.error("查询用户信息为空userId："+carOrderBizDto.getUserId());
                throw new Exception("查询用户信息为空userId："+carOrderBizDto.getUserId());
            }
            //车辆所在
            maintenanceEmailDto.setVehicleLocation(dealerDto.getShortName()+ "-" + userDto.getRealName());
            maintenanceEmailDto.setOrderCode(carOrderBizDto.getOrderCode());
            maintenanceEmailDto.setUserName(userDto.getRealName());
            maintenanceEmailDto.setUserPhone(userDto.getPhone());
        }
        maintenanceEmailDto.setVin(carDto.getVin());
        maintenanceEmailDto.setLicencePlate(carDto.getLicencePlate());
        maintenanceEmailDto.setNowMileage(nowMileage.intValue());
        if(type == 1){
            maintenanceEmailDto.setMaintainableMileage(maintenanceDto.getMaintainableMileage().intValue());
            maintenanceEmailDto.setMaintainableDate(DateUtil.formatTime(maintenanceDto.getMaintainableDate()));
        }else{
            maintenanceEmailDto.setMaintainableMileage(maintenanceConfig.get(carDto.getVehicleId()).getMileage().intValue());
            maintenanceEmailDto.setMaintainableDate(DateUtil.formatTime(DateUtil.getDayEnd(carDto.getPurchaseDate().plusDays(maintenanceConfig.get(carDto.getVehicleId()).getMaintenanceTime()))));
        }

        return maintenanceEmailDto;
    }




    /**
     * 创建保养
     * @param carOrderBizDto
     * @param carDto
     * @param maintenanceConfig
     * @return
     * @throws Exception
     */
    private Integer createMaintenance(CarOrderBizDto carOrderBizDto,CarDto carDto,Map<Integer,MaintenanceConfigDto> maintenanceConfig){

        MaintenanceDto maintenanceCreateDto = new MaintenanceDto();
        maintenanceCreateDto.setCode(DateUtil.formatLocalDateNow()+(int)((Math.random()*9+1)*10000));
        if(null != carOrderBizDto){
            maintenanceCreateDto.setOrderCode(carOrderBizDto.getOrderCode());
            maintenanceCreateDto.setUserId(carOrderBizDto.getUserId());
        }
        maintenanceCreateDto.setStatus(MaintenanceStatusEnum.WAITING_MAINTENANCE.getValue());
        maintenanceCreateDto.setCarId(carDto.getId());
        maintenanceCreateDto.setMaintainableMileage(maintenanceConfig.get(carDto.getVehicleId()).getMileage());
        maintenanceCreateDto.setMaintainableDate(DateUtil.getDayEnd(carDto.getPurchaseDate().plusDays(maintenanceConfig.get(carDto.getVehicleId()).getMaintenanceTime())));
        maintenanceCreateDto.setPurchaseDate(carDto.getPurchaseDate());
        maintenanceCreateDto.setCount(0);
        Integer maintenanceId = maintenanceService.createMaintenance(maintenanceCreateDto);
        return maintenanceId;

    }


    /**
     * 创建保养
     * @param carOrderBizDto
     * @param maintenanceDto
     * @return
     * @throws Exception
     */
    private void updateMaintenanceById(CarOrderBizDto carOrderBizDto,MaintenanceDto maintenanceDto){

        MaintenanceDto maintenanceUpdateDto = new MaintenanceDto();
        if(null != carOrderBizDto && (null == maintenanceDto.getOrderCode() || !maintenanceDto.getOrderCode().equals(carOrderBizDto.getOrderCode()))){

            maintenanceUpdateDto.setOrderCode(carOrderBizDto.getOrderCode());
            maintenanceUpdateDto.setUserId(carOrderBizDto.getUserId());
        }
        maintenanceUpdateDto.setId(maintenanceDto.getId());
        maintenanceUpdateDto.setStatus(MaintenanceStatusEnum.WAITING_MAINTENANCE.getValue());
        maintenanceService.updateMaintenanceById(maintenanceUpdateDto);

    }


    /**
     * 保养发送钉钉
     * @param type 1:预警，2：超期
     * @param map
     */
    private void sendMaintenanceDingTalk(Integer type ,Map<String, MessageTemplateDto> map) {
        MessageTemplateDto dto = map.get(dingTalkMaintenanceOvertime);
        if(1 == type){
            dto = map.get(dingTalkMaintenanceWarning);
        }
        if(null == dto) {
            return;
        }
        String body = dto.getBody();
        if(StringUtils.isNoneBlank(body)) {
            DingTalkUtil.execute(dingTalkMaintenanceUrl, body);
        }
    }

    /**
     * 保养发送邮件
     * @param type 1:预警，2：超期
     * @param map
     * @param list
     */
    private void sendMaintenanceEmail(Integer type ,Map<String, MessageTemplateDto> map, List<MaintenanceEmailDto> list) {
        MessageTemplateDto dto = map.get(emailMaintenanceOvertime);
        if(1 == type){
            dto = map.get(emailMaintenanceWarning);
        }
        if(null == dto) {
            return;
        }
        try {
            String subject = dto.getSubject();
            String body = dto.getBody();
            if(StringUtils.isNoneBlank(subject) && StringUtils.isNoneBlank(body)) {
                subject= subject+"(年份)";
                List<String> emailTo = getEmail();
                String fileName = subject + ".xlsx";
                ByteArrayInputStream is = toExcel(list);
                EmailUtil.sendMail(emailAccount, emailPassword, subject,body,emailTo,fileName,is);
            }
        } catch (Exception e) {
            logger.error("发送邮件异常",e);
        }
    }


    /**
     * 组装邮件附件
     * @param list
     * @return
     */
    private ByteArrayInputStream toExcel(List<MaintenanceEmailDto> list) {
        ByteArrayOutputStream baos = null;
        ByteArrayInputStream is = null;
        try {
            List<String> titles =new  ArrayList<>();
            titles.add(0, "订单号");
            titles.add(1, "车架号");
            titles.add(2, "车牌号");
            titles.add(3, "车辆所在");
            titles.add(4, "用户姓名");
            titles.add(5, "联系电话");
            titles.add(6, "已行驶里程");
            titles.add(7, "应保养里程");
            titles.add(8, "应保养日期");
            List<List<String>> params=new ArrayList<>();
            for (MaintenanceEmailDto dto : list) {
                List<String> contents=new ArrayList<>();
                if(null != dto.getOrderCode()){
                    contents.add(0,dto.getOrderCode().toString());
                }else{
                    contents.add(0,"-");
                }
                contents.add(1,dto.getVin());
                contents.add(2,dto.getLicencePlate());
                contents.add(3,dto.getVehicleLocation());
                if(null != dto.getUserName()){
                    contents.add(4,dto.getUserName());
                }else{
                    contents.add(4,"-");
                }
                if(null != dto.getUserPhone()){
                    contents.add(5,dto.getUserPhone());
                }else{
                    contents.add(5,"-");
                }
                contents.add(6,dto.getNowMileage().toString());
                contents.add(7,dto.getMaintainableMileage().toString());
                contents.add(8,dto.getMaintainableDate());
                params.add(contents);
            }
            XSSFWorkbook createXSSFWorkbook = PoiExcelUtils.createXSSFWorkbook(titles, params);
            baos = new ByteArrayOutputStream();
            createXSSFWorkbook.write(baos);
            baos.flush();
            is = new ByteArrayInputStream(baos.toByteArray());

        } catch (Exception e) {
            logger.error("保养预警发送邮件异常:", e);
        }finally {
            if(null!= baos) {
                try {
                    baos.close();
                } catch (IOException e) {

                }
            }
        }
        return is;
    }

    /**
     * 获取邮件人信息
     * @return
     */
    private List<String> getEmail(){
        List<RiskEmailDto> riskList = riskEmailService.getByType(RiskEmailTypeEnum.MAINTENANCE_NOTICE.getValue(), RiskEmailReceiveTypeEnum.EMAIL_RECIPIENT.getValue());

        List<String> list=null;
        if(null != riskList && !riskList.isEmpty()) {
            list=new ArrayList<>();
            for (RiskEmailDto dto : riskList) {
                list.add(dto.getEmail());
            }
        }
        return list;
    }



    /**
     * 查询模板信息
     * @return
     */
    private Map<String,MessageTemplateDto> getDingAndEmailByKeys(){
        List<String> keys= new ArrayList<>();
        keys.add(dingTalkMaintenanceOvertime);
        keys.add(dingTalkMaintenanceWarning);
        keys.add(emailMaintenanceOvertime);
        keys.add(emailMaintenanceWarning);
        try {
            Map<String,MessageTemplateDto> map = messageTemplateService.getByKey(keys);
            return map;
        } catch (Exception e) {
            logger.error("查询消息模板异常",e);
            return null;
        }
    }

    /**
     * 发送短信，站内信和推送
     * @param userId
     * @param carDto
     * @throws Exception
     */
    private void sendNoteAndPush(Integer userId,CarDto carDto) throws Exception {
        UserDto userDto = userService.getUser(userId);
        if(null == userDto){
            logger.error("查询用户信息为空userId："+ userId);
            throw new Exception("查询用户信息为空userId："+ userId);
        }
        //发送短信
        sendNote(userDto.getPhone(),carDto);
        //推送和站内信
        sendPush(userDto.getId(),userDto.getPhone(),carDto);
    }

    /**
     * 保养发送短信
     * @param phone
     * @param carDto
     */
    private void sendNote(String phone,CarDto carDto) {
        JSONObject json=new JSONObject();
        json.put("plate", carDto.getLicencePlate());
        try {
            smsBizService.sendMessage(phone, SmsTemplateEnum.MAINTENANCE_REMINDER.getValue(), json.toJSONString(), null);
        } catch (Exception e) {
            logger.error("保养发送短信失败",e);
        }
    }


    /**
     * 车辆保养提醒消息推送
     * @param userId
     * @param phone
     * @param carDto
     */
    private void sendPush(Integer userId,String phone,CarDto carDto) {
        try {
            Map<String, MessageTemplateDto> map = getPushByKeys();
            if(null != map) {
                //psuh
                NotifyPushCreateDto notifyPush = getNotifyPush(phone,map,carDto);
                notifyPushService.notifyPushByAlias(notifyPush);
                //保存站内信息
                MessageCenterCreateDto messageCenter = getMessageCenter(userId,map,carDto);
                messageCenterService.createMessageCenter(messageCenter);
            }
        } catch (Exception e) {
            logger.error("车辆保养提醒消息推送失败",e);
        }
    }


    /**
     * 获取instation实体
     * @param userId
     * @param carDto
     * @param map
     * @return
     */
    private MessageCenterCreateDto getMessageCenter(Integer userId,Map<String,MessageTemplateDto> map,CarDto carDto) {
        MessageCenterCreateDto dto =new MessageCenterCreateDto();
        dto.setUserId(userId);
        MessageTemplateDto messageTemplateDto = map.get(instationMaintenanceRemind);
        dto.setTitle(messageTemplateDto.getSubject());
        String body = messageTemplateDto.getBody();
        body = body.replace("${licencePlate}", carDto.getLicencePlate());
        dto.setMessage(body);
        dto.setType(MessageCenterTypeEnum.MAINTENANCE_REMINDER.getValue());
        dto.setStatus(MessageCenterStatusEnum.UNREAD.getValue());
        return dto;
    }


    /**
     * 获取psuh实体
     * @param phone
     * @param map
     * @param carDto
     * @return
     */
    private NotifyPushCreateDto getNotifyPush(String phone,Map<String,MessageTemplateDto> map,CarDto carDto) {
        NotifyPushCreateDto dto =new NotifyPushCreateDto();
        ArrayList<String> alias = new ArrayList<>(1);
        alias.add(phone);
        dto.setAlias(alias);
        MessageTemplateDto messageTemplateDto = map.get(pushMaintenanceRemind);
        dto.setNotifyTitle(messageTemplateDto.getSubject());
        dto.setMsgTitle(messageTemplateDto.getSubject());
        String body = messageTemplateDto.getBody();
        body = body.replace("${licencePlate}", carDto.getLicencePlate());
        dto.setIosMsgContent(body);
        dto.setAndroidMsgContent(body);
        return dto;
    }



    /**
     * 查询模板信息
     * @return
     */
    private Map<String,MessageTemplateDto> getPushByKeys(){
        List<String> keys= new ArrayList<>();
        keys.add(pushMaintenanceRemind);
        keys.add(instationMaintenanceRemind);
        try {
            Map<String,MessageTemplateDto> map = messageTemplateService.getByKey(keys);
            return map;
        } catch (Exception e) {
            logger.error("查询消息模板异常",e);
            return null;
        }
    }
}
